package com.wl.lib.mvi

import android.util.Log
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.wl.lib.base.R
import com.wl.lib.http.NetworkHelper
import com.wl.lib.utils.ResUtils
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.launch

// Created by wangliang on 2024/4/24.
abstract class BaseViewModel<UiIntent : IUiIntent, UiEvent : IUiEvent> : ViewModel() {

    companion object {
        private const val TAG = "BaseViewModel"
    }

    // StateFlow 是具有可变状态的单值数据流，只能有一个订阅者

    // 页面整体状态
    val loadUiState = MutableStateFlow<LoadUiState>(LoadUiState.INIT)

    private val _uiIntentFlow: Channel<UiIntent> = Channel()
    private val uiIntentFlow: Flow<UiIntent> = _uiIntentFlow.receiveAsFlow()

    val uiEvent = MutableSharedFlow<UiEvent>()

    fun sendUiIntent(uiIntent: UiIntent) {
        viewModelScope.launch {
            _uiIntentFlow.send(uiIntent)
        }
    }

    init {
        viewModelScope.launch {
            uiIntentFlow.collect {
                handleIntent(it)
            }
        }
    }

    /**
     * 子类实现此方法处理所以页面发过来的 Intent，就是各种事件的处理
     */
    protected abstract fun handleIntent(intent: IUiIntent)

    // 是不是首次加载，默认情况下只有一个请求是首次加载，后面考虑优化如何合并请求作为首次加载
    var firstLoadFinished = false
        private set

    protected fun <T : Any> requestDataWithFlow(
        firstLoad: Boolean = false, // 一个页面首个加载的请求
        showLoading: Boolean = false,
        request: suspend () -> BaseData<T>,
        successCallback: (T) -> Unit,
        failCallback: suspend (String) -> Unit = { errMsg ->
            //默认异常处理，子类可以进行覆写
            loadUiState.value = LoadUiState.Error(errMsg)
        }
    ) {
        viewModelScope.launch {
            //是否展示Loading
            if (showLoading) {
                loadUiState.value = LoadUiState.Loading(true)
            }
            val baseData: BaseData<T>
            try {
                baseData = request()

                if (showLoading) {
                    loadUiState.value = LoadUiState.Loading(false)
                }
                when (baseData.state) {
                    ReqState.Success -> {
                        if (firstLoad) {
                            loadUiState.value = LoadUiState.ShowMainView
                        }
                        baseData.data?.let { successCallback(it) }
                    }
                    ReqState.Error -> {
                        Log.e(TAG, "request error code: ${baseData.code} msg: ${baseData.msg}")
                        failCallback(
                            baseData.msg ?: ResUtils.getString(R.string.default_request_error)
                        )
                    }
                }
            } catch (e: Exception) {
                if (showLoading) {
                    loadUiState.value = LoadUiState.Loading(false)
                }
                Log.e(TAG, "request error $e")
                e.message?.let { failCallback(NetworkHelper.getDefaultRequestErrorMsg()) }
            }
        }
    }

    override fun onCleared() {
        super.onCleared()
        _uiIntentFlow.close()
    }
}
